`timescale 1ns / 1ps
`include "def.v"


module control(
    input [31:0] Instr,

    output [4:0] rt,
    output [4:0] rs,
    output [4:0] rd,
    output [4:0] shamt,
    output [15:0] imm16,
    output [25:0] imm26,

    output [3:0] ALUOp,
    output [2:0] BJPOp, 
    output [4:0] GRFWrReg,
    output [1:0] GRFWDtype,
    output [1:0] ALUBtype,
    output [1:0] ALUAtype,
    output DMWrEn,
    output EXTOp,
    output [2:0] NPCOp,

    output load,
    output store,
    output calc_r,
    output calc_i,
    output branch,
    output jump_reg,
    output jump_addr,
    output jump_link
    );

    // 译码
    wire [5:0] opcode = Instr[31:26];
    wire [5:0] funct = Instr[5:0];
    assign rs = Instr[25:21];
    assign rt = Instr[20:16];
    assign rd = Instr[15:11];
    assign imm16 = Instr[15:0];
    assign imm26 = Instr[25:0];
    assign shamt = Instr[10:6];

    //均不是默认为 nop ，共十条指令
    wire addu = (opcode == `op_R && funct == `fun_ADDU);
    wire subu = (opcode == `op_R && funct == `fun_SUBU);
    wire ori = (opcode == `op_ORI);
    wire lui = (opcode == `op_LUI);
    wire lw = (opcode == `op_LW);
    wire sw = (opcode == `op_SW);
    wire beq = (opcode == `op_BEQ);
    wire jal = (opcode == `op_JAL);
    wire jr = (opcode == `op_JR && funct == `fun_JR);
    
    
    // 控制信号生成
    assign ALUOp = (subu) ? `ALU_sub :
                   (ori) ? `ALU_or :
                   (lui) ? `ALU_lui :
                   `ALU_add;
    assign EXTOp = (load | store) ? `EXT_sign :`EXT_unsign;
    assign BJPOp = (beq) ? `BJP_beq :3'b0;
    assign NPCOp = (branch) ? `NPC_b :
                   (jump_addr) ? `NPC_jal :
                   (jump_reg) ? `NPC_jr :
                   `NPC_pc4;

    assign DMWrEn = store;
    assign GRFWDtype = (jump_link) ? `WDtype_pc8 :
                      (load) ? `WDtype_dmrd :
                      `WDtype_aluans;

    assign GRFWrReg = (calc_r) ? rd :
                   (calc_i | load) ? rt :
                   (jal ) ? 5'd31 :
                   5'd0;

    assign ALUBtype = (calc_r) ? `Btype_rt : 
                     (calc_i | load | store) ? `Btype_imm :
                     `Btype_rt;

    assign ALUAtype = `Atype_rs;


    assign load   = lw ;
    assign store  = sw ;
    assign branch = beq; 

    assign calc_r = addu | subu;
    assign calc_i = ori | lui;

    assign jump_reg  = jr ;
    assign jump_addr = jal;
    assign jump_link = jal;
endmodule
